package com.ihg.hiex.admin.service.session.impl;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.demo2do.core.entity.exception.BusinessException;
import com.demo2do.core.entity.page.Page;
import com.demo2do.core.persistence.GenericDaoSupport;
import com.demo2do.core.persistence.annotation.Dao;
import com.demo2do.core.utils.DateFormatUtils;
import com.ihg.hiex.admin.Constants;
import com.ihg.hiex.admin.dao.account.AccountDao;
import com.ihg.hiex.admin.dao.account.AdministratorDao;
import com.ihg.hiex.admin.dao.account.AssessorDao;
import com.ihg.hiex.admin.dao.account.DelegateDao;
import com.ihg.hiex.admin.dao.account.KnowingRelationDao;
import com.ihg.hiex.admin.dao.data.ConferenceRoomDao;
import com.ihg.hiex.admin.dao.session.EmailTemplateDao;
import com.ihg.hiex.admin.dao.session.SessionDao;
import com.ihg.hiex.admin.dao.session.SessionFacilitatorDao;
import com.ihg.hiex.admin.dao.session.SessionParticipatorDao;
import com.ihg.hiex.admin.dao.session.SessionParticipatorRecordDao;
import com.ihg.hiex.admin.dao.session.SessionTaskDao;
import com.ihg.hiex.admin.entity.search.SessionReportSearch;
import com.ihg.hiex.admin.entity.security.Login;
import com.ihg.hiex.admin.entity.session.FacilitatorConferenceRoom;
import com.ihg.hiex.admin.entity.session.FinishTask;
import com.ihg.hiex.admin.handler.DateHandler;
import com.ihg.hiex.admin.processor.FtpProcessor;
import com.ihg.hiex.admin.service.DataServiceImpl;
import com.ihg.hiex.admin.service.session.SessionService;
import com.ihg.hiex.entity.data.conference.ConferenceRoom;
import com.ihg.hiex.entity.data.notice.EmailTemplate;
import com.ihg.hiex.entity.session.Session;
import com.ihg.hiex.entity.session.SessionAttribute;
import com.ihg.hiex.entity.session.SessionNotification;
import com.ihg.hiex.entity.session.Status;
import com.ihg.hiex.entity.session.after.SessionReport;
import com.ihg.hiex.entity.session.event.SessionEvent;
import com.ihg.hiex.entity.session.event.Type;
import com.ihg.hiex.entity.session.meeting.SessionMeeting;
import com.ihg.hiex.entity.session.meeting.Target;
import com.ihg.hiex.entity.session.participator.SessionFacilitator;
import com.ihg.hiex.entity.session.participator.SessionParticipator;
import com.ihg.hiex.entity.session.participator.SessionParticipatorRecord;
import com.ihg.hiex.entity.session.task.SessionTask;
import com.ihg.hiex.entity.session.task.SessionTaskType;
import com.ihg.hiex.entity.user.Account;
import com.ihg.hiex.entity.user.Administrator;
import com.ihg.hiex.entity.user.Assessor;
import com.ihg.hiex.entity.user.Delegate;
import com.ihg.hiex.entity.user.KnowingRelation;
import com.ihg.hiex.entity.user.Role;

/**
 * 
 * @author houtao
 *
 */
@Service("sessionService")
public class SessionServiceImpl extends DataServiceImpl<Session> implements SessionService {

    @Autowired
    private GenericDaoSupport genericDaoSupport;

    @Dao
    private SessionDao sessionDao;
    
    @Dao
    private AdministratorDao administratorDao;
    
    @Dao
    private AssessorDao assessorDao;
    
    @Dao
    private DelegateDao delegateDao;
    
    @Dao
    private AccountDao accountDao;
    
    @Dao
    private SessionParticipatorDao sessionParticipatorDao;
    
    @Dao
    private SessionFacilitatorDao sessionFacilitatorDao;
    
    @Dao
    private ConferenceRoomDao conferenceRoomDao;
    
    @Dao
    private SessionParticipatorRecordDao sessionParticipatorRecordDao;
    
    @Dao
    private KnowingRelationDao knowingRelationDao;
    
    @Dao
    private SessionTaskDao sessionTaskDao;
    
    @Dao
    private EmailTemplateDao emailTemplateDao;
    
    @Autowired
    private DateHandler dateHandler;
    
    @Autowired
    private FtpProcessor ftpProcessor;
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#count(com.ihg.hiex.entity.session.SessionStatus)
     */
    public int count(Status status) {
        return sessionDao.count(status);
    }
    
    /* (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#count(com.ihg.hiex.admin.entity.security.Login, com.ihg.hiex.entity.session.Status)
     */
    public int count(Login login, Status status) {
        
        if (login.isAdministrator()) {          // if current user is administrator get this administrator's all active sessions
            
            Administrator admin = genericDaoSupport.load(Administrator.class, login.getId());
            return sessionDao.count(status, admin);
            
        } else if (login.isSupervisor()) {      // if current user is supervisor get all active sessions
            
            return sessionDao.count(status);
            
        } else {
            return 0;           // FIXME
        }
        
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#count(com.ihg.hiex.admin.entity.security.Login)
     */
    public int count(Login login) {
        
        if(login.isSupervisor()) {  // if current user is supervisor get all active sessions
            
            return sessionDao.count();
            
        } else {  // if current user is administrator get this administrator's all active sessions
            
            Administrator admin = genericDaoSupport.load(Administrator.class, login.getId());
            return sessionDao.count(admin);
            
        }
        
    }
    
     /*
      * (non-Javadoc)
      * @see com.ihg.hiex.admin.service.session.SessionService#list(com.ihg.hiex.entity.session.SessionStatus, com.demo2do.core.entity.page.Page)
      */
     public List<Session> list(Status status, Page page) {
         List<Session> sessions = sessionDao.list(status, page.getBeginIndex(), page.getEveryPage());
         page.calculate();
         return sessions;
     }
     
     /*
      * (non-Javadoc)
      * @see com.ihg.hiex.admin.service.session.SessionService#list(com.ihg.hiex.admin.entity.security.Login, com.ihg.hiex.entity.session.Status, com.demo2do.core.entity.page.Page)
      */
     public List<Session> list(Login login, Status status, Page page) {
         
         List<Session> sessions = new ArrayList<Session>();
         
         if(login.isAdministrator()) {          // if current user is administrator get this administrator's all active sessions
             
             Administrator admin = genericDaoSupport.load(Administrator.class, login.getId());
             sessions = sessionDao.list(status, admin, page.getBeginIndex(), page.getMaxResultRecords());
             
         } else if (login.isSupervisor()) {     // if current user is supervisor get all active sessions
             
             sessions = sessionDao.list(status, page.getBeginIndex(), page.getMaxResultRecords());
             
         }
         
         page.calculate();
         return sessions;
         
     }
     
     /*
      * (non-Javadoc)
      * @see com.ihg.hiex.admin.service.session.SessionService#list(com.ihg.hiex.entity.session.Status)
      */
     public List<Session> list(Status status) {
         return sessionDao.list(status);
     }
     
     /*
      * (non-Javadoc)
      * @see com.ihg.hiex.admin.service.session.SessionService#list(com.ihg.hiex.entity.session.Status, com.ihg.hiex.entity.user.Administrator)
      */
     public List<Session> list(Status status, Administrator administrator) {
         return sessionDao.list(status, administrator);
     }
     
     /*
      * (non-Javadoc)
      * @see com.ihg.hiex.admin.service.session.SessionService#list(com.ihg.hiex.entity.session.Status, com.ihg.hiex.entity.user.Assessor)
      */
     public List<Session> list(Status status, Assessor assessor) {
         return sessionParticipatorDao.listSessionByAssessor(status, assessor.getId());
     }
     
     /*
      * (non-Javadoc)
      * @see com.ihg.hiex.admin.service.session.SessionService#list(com.ihg.hiex.entity.session.Status, com.ihg.hiex.entity.user.Delegate)
      */
     public List<Session> list(Status status, Delegate delegate) {
         return sessionParticipatorDao.listBySessionDelegate(status, delegate.getId());
     }
     
     /*
      * (non-Javadoc)
      * @see com.ihg.hiex.admin.service.session.SessionService#list(com.ihg.hiex.admin.entity.security.Login, com.demo2do.core.entity.page.Page)
      */
     public List<Session> list(Login login, Page page) {
         
         List<Session> sessions = new ArrayList<Session>();
         
         if(login.isSupervisor()) {  // if current user is supervisor get all active sessions
             sessions = sessionDao.list(page.getBeginIndex(), page.getMaxResultRecords());
         } else {  // if current user is administrator get this administrator's all active sessions
             Administrator admin = genericDaoSupport.load(Administrator.class, login.getId());
             sessions = sessionDao.list(admin, page.getBeginIndex(), page.getMaxResultRecords());
         }
         
         page.calculate();
         return sessions;
         
     }
     
     /*
      * (non-Javadoc)
      * @see com.ihg.hiex.admin.service.session.SessionService#list(com.ihg.hiex.entity.user.Administrator)
      */
     public List<Session> list(Administrator administrator) {
         return sessionDao.list(administrator);
     }
     
     /*
      * (non-Javadoc)
      * @see com.ihg.hiex.admin.service.session.SessionService#list(java.util.List)
      */
    @SuppressWarnings("unchecked")
    public List<Session> list(List<Delegate> delegates) {
        List<Long> delegateIds = com.demo2do.core.utils.CollectionUtils.extractPropertyList(delegates, "id");
        return sessionDao.list(delegateIds);
    }
     
     /*
      * (non-Javadoc)
      * @see com.ihg.hiex.admin.service.session.SessionService#listSessionAttribute(com.ihg.hiex.entity.session.Session, java.lang.String[])
      */
     public Map<String, SessionAttribute> listSessionAttribute(Session session, String[] names) {
        List<SessionAttribute> sessionAttributes = sessionDao.listSessionAttribute(session, names);
        return com.demo2do.core.utils.CollectionUtils.constructMapValue(sessionAttributes, "name");
     }
     
     /*
      * (non-Javadoc)
      * @see com.ihg.hiex.admin.service.session.SessionService#listSessionAttribute(java.util.List, java.lang.String[])
      */
     public Map<String, Map<String, SessionAttribute>> listSessionAttribute(List<Session> sessions, String[] names) {
         List<SessionAttribute> sessionAttributes = sessionDao.listSessionAttribute(sessions, names);
         Map<String, List<SessionAttribute>> attributes = com.demo2do.core.utils.CollectionUtils.constructMapValues(sessionAttributes, "session.id");
         
         Map<String, Map<String, SessionAttribute>> result = new HashMap<String, Map<String, SessionAttribute>>();
         for(String key : attributes.keySet()) {
             result.put(key, com.demo2do.core.utils.CollectionUtils.constructMapValue(attributes.get(key), "name"));
         }
        return result;
     }
     
     /*
      * (non-Javadoc)
      * @see com.ihg.hiex.admin.service.session.SessionService#listSessionReport(com.ihg.hiex.admin.entity.search.SessionReportSearch, com.demo2do.core.entity.page.Page)
      */
    @SuppressWarnings("unchecked")
    public Map<String, Map<String, SessionReport>> searchSessionReport(SessionReportSearch search) {
        List<SessionReport> sessionReports = genericDaoSupport.searchForList(search.buildSentenceTemplate(), search.buildParameters());
        
        Map<String, List<SessionReport>> reports = new HashMap<String, List<SessionReport>>();
        if(search.getSession() != null) {
            reports = com.demo2do.core.utils.CollectionUtils.constructMapValues(sessionReports, "delegate.name");
        } else {
            reports =  com.demo2do.core.utils.CollectionUtils.constructMapValues(sessionReports, "session.name");
        }
        
        Map<String, Map<String, SessionReport>> result = new HashMap<String, Map<String, SessionReport>>();
        for(Entry<String, List<SessionReport>> report : reports.entrySet()) {
            result.put(report.getKey(), com.demo2do.core.utils.CollectionUtils.constructMapValue(report.getValue(), "type"));
        }
        
        return result;
    }
     
     /*
      * (non-Javadoc)
      * @see com.ihg.hiex.admin.service.session.SessionService#load(java.lang.Long)
      */
    public Session load(Long sessionId) {
        return genericDaoSupport.load(Session.class, sessionId);
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#loadSessionTask(com.ihg.hiex.entity.session.Session, java.lang.String)
     */
    public SessionTask loadSessionTask(Session session, String taskName) {
        return sessionDao.loadSessionTask(session, taskName);
    }
    
    /* (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#create(com.ihg.hiex.entity.session.Session, java.util.List, java.util.List, java.lang.String, java.lang.String, java.lang.Long, java.lang.String)
     */
    public void create(Session session, List<Assessor> assessors, List<Delegate> delegates, String assessorWechatGroup, String delegateWechatGroup, Long operatorId, String operator) {
        
        // validate if assessors or delegates is empty throw business exception
        if(CollectionUtils.isEmpty(assessors) || CollectionUtils.isEmpty(delegates)) {
            throw new BusinessException("Assessor and Delegate can's be empty");
        }
        
        // validate if assessors'size invalid or delegate's size invalid
        int defectDelegates = assessors.size()*2 - delegates.size();
        if (assessors.size() % 2 != 0 || defectDelegates >= 3) {
            throw new BusinessException("Assessor or Delegate size invalid");
        }
        
        // 1.1 save session
        Administrator sessionHost = genericDaoSupport.load(Administrator.class, operatorId);
        session.initialize(sessionHost, assessors.size(), delegates.size(), assessorWechatGroup, delegateWechatGroup, operatorId);
        genericDaoSupport.save(session);
        
        // 1.2 save session event
        this.createSessionEvent(session, Type.CREATE, "create", operatorId, operator);
        
        // 2.1 save assessors
        assessors = this.createAssessors(assessors);
        
        // 2.2 save delegates
        delegates = this.createDelegates(delegates);
        
        // 2.3 create session participator
        this.createSessionParticipator(assessors, delegates, session, operatorId);
        
        // 3. create relation of assessor--conferenceRoom.
        this.bindConferenceRoom(assessors);
        
        // 4.1 create assessor's orientation call meeting
        Date assessorOrientationCallStartTime = dateHandler.calculateWorkDay(session.getStartDate(), 12, "16:00");
        Date assessorOrientationCallEndTime = dateHandler.calculateWorkDay(session.getStartDate(), 12, "17:30");
        this.createSessionMeeting(session, "Orientation Call", assessorOrientationCallStartTime, assessorOrientationCallEndTime, 
                                  session.getAssessorOwner().getId(), session.getAssessorOwner().getConferenceRoom(),
                                  Target.ADMIN_ASSESSORS, com.ihg.hiex.entity.session.meeting.Type.LARGE_GROUP);
        
        // 4.2 create delegate's orientation call meeting
        Date delegateOrientationCallStartTime = dateHandler.calculateWorkDay(session.getStartDate(), 12, "14:00");
        Date delegateOrientationCallEndTime = dateHandler.calculateWorkDay(session.getStartDate(), 12, "15:30");
        this.createSessionMeeting(session, "Orientation Call", delegateOrientationCallStartTime, delegateOrientationCallEndTime,
                                  session.getDelegateOwner().getId(), session.getDelegateOwner().getConferenceRoom(),
                                  Target.ADMIN_DELEGATES, com.ihg.hiex.entity.session.meeting.Type.LARGE_GROUP);
        
        // 4.3 create assessor Q&A Call Meeting
        List<ConferenceRoom> bigZoomRooms = conferenceRoomDao.list(com.ihg.hiex.entity.data.conference.Type.BigZoom);
        Date assessorQaCallStartTime = dateHandler.calculateWorkDay(session.getStartDate(), 2, "16:00");
        Date assessorQaCallEndTime = dateHandler.calculateWorkDay(session.getStartDate(), 2, "17:30");
        this.createSessionMeeting(session, "Q&A Call", assessorQaCallStartTime, assessorQaCallEndTime,
                                  session.getAssessorOwner().getId(), bigZoomRooms.get(0),
                                  Target.ADMIN_ASSESSORS, com.ihg.hiex.entity.session.meeting.Type.LARGE_GROUP);
        
        // 4.4 create delegate Q&A Call Meeting
        Date delegateQaCallStartTime = dateHandler.calculateWorkDay(session.getStartDate(), 2, "14:00");
        Date delegateQaCallEndTime = dateHandler.calculateWorkDay(session.getStartDate(), 2, "15:30");
        this.createSessionMeeting(session, "Q&A Call", delegateQaCallStartTime, delegateQaCallEndTime,
                                  session.getDelegateOwner().getId(), bigZoomRooms.get(1),
                                  Target.ADMIN_DELEGATES, com.ihg.hiex.entity.session.meeting.Type.LARGE_GROUP);
    
        // 5. create session_notification
        this.createSessionNotification(session);
        
    }
    
    /* (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#reUpload(com.ihg.hiex.entity.session.Session, java.util.List, java.util.List, java.lang.Long, java.lang.String)
     */
    public void reUpload(Session session, List<Assessor> assessors, List<Delegate> delegates, Long operatorId, String operator) {
        
        // validate if assessors or delegates is empty throw business exception
        if(CollectionUtils.isEmpty(assessors) || CollectionUtils.isEmpty(delegates)) {
            throw new BusinessException("Assessor and Delegate can's be empty");
        }
        
        // validate if assessors'size invalid or delegate's size invalid
        int defectDelegates = assessors.size()*2 - delegates.size();
        if (assessors.size() % 2 != 0 || defectDelegates >= 3) {
            throw new BusinessException("Assessor or Delegate size invalid");
        }
        
        // 1.1 delete old assessor-conferenceRoom relation
        List<Long> oldAssessorIds = sessionParticipatorDao.listAssessor(session);
        List<Assessor> oldAssessors = assessorDao.list(oldAssessorIds);
        for (Assessor assessor : oldAssessors) {
            genericDaoSupport.update(assessor.editZoomRoom(null));
        }
        
        // 1.2 delete old sessionParticipator
        sessionParticipatorDao.delete(session);
        
        // 2.1 save assessors
        assessors = this.createAssessors(assessors);
        
        // 2.2 save delegates
        delegates = this.createDelegates(delegates);
        
        // 2.3 create session participator
        this.createSessionParticipator(assessors, delegates, session, operatorId);
        
        // 3. create relation of assessor--conferenceRoom.
        this.bindConferenceRoom(assessors);
        
        // 4.1 update session
        genericDaoSupport.update(session.edit(assessors.size(), delegates.size(), operatorId));
        
        // 4.2 save session event
        this.createSessionEvent(session, Type.EDIT, "edit", operatorId, operator);
        
    }
    
    /**
     * create assessor
     * 
     * @param assessor
     * @return
     */
    private Assessor createAssessor(Assessor assessor) {
        
        String email = assessor.getEmail().toLowerCase();

        // 1. judge account whether exist
        Account account = null;
        Account existAccount = accountDao.loadByEmail(email);
        if (existAccount != null) {     // 2.1 exist admin account, save assessor and update account
            genericDaoSupport.update(existAccount.addAuthority("ASSESSOR"));
            account = existAccount;
        } else {                        // 2.2 not exist account, save assessor and save account
            account = new Account(assessor);
            genericDaoSupport.save(account.initialize());
        }
        
        // 2. judge assessor whether exist, if not exist save assessor
        Assessor exist = assessorDao.loadByEmail(email);
        if(exist != null) {
            return exist;
        } else {
            genericDaoSupport.save(assessor.initialize(account));
            return assessor;
        }

    }
    
    /**
     * 
     * @param delegates
     * @param session
     * @param operator
     */
    private Delegate createDelegate(Delegate delegate) {
        
        String email = delegate.getEmail().toLowerCase();
        
        // 1. judge account whether exist, if not exist add account
        Account account = null;
        Account existAccount = accountDao.loadByEmail(email);
        if (existAccount != null) {     // 1.1 exist admin account, save assessor and update account
            genericDaoSupport.update(existAccount.addAuthority("DELEGATE"));
            account = existAccount;
        } else {                        // 1.2 not exist account, save assessor and save account
            account = new Account(delegate);
            genericDaoSupport.save(account.initialize());
        }
        
        // 2. judge delegate whether exist, if not exist save delegate
        Delegate exist = delegateDao.load(email);
        if(exist != null) {
            return exist;
        } else {
            genericDaoSupport.save(delegate.initialize(account));
            return delegate;
        }
        
    }
    
    /**
     * 
     * @param newAssessors
     * @return
     */
    private List<Assessor> createAssessors(List<Assessor> newAssessors) {
        
        List<Assessor> assessors = new LinkedList<Assessor>();
        
        // create assessor and assessor account
        for (Assessor newAssessor : newAssessors) {
            Assessor assessor = this.createAssessor(newAssessor);
            assessors.add(assessor);
        }
        
        return assessors;
        
    }
    
    /**
     * 
     * @param newDelegates
     * @return
     */
    private List<Delegate> createDelegates(List<Delegate> newDelegates) {
        
        List<Delegate> delegates = new LinkedList<Delegate>();
        
        // create delegate and delegate account
        for (Delegate newDelegate : newDelegates) {
            Delegate delegate = this.createDelegate(newDelegate);
            delegates.add(delegate);
        }
        
        return delegates;
        
    }
    
    /**
     * @param assessors
     * @param delegates
     * @param session
     * @param operator
     */
    private void createSessionParticipator(List<Assessor> assessors, List<Delegate> delegates, Session session, Long operator) {
        
        int assessorSize = assessors.size();
        int delegateSize = delegates.size();
        
        if (assessorSize * 2 == delegateSize) {         // assessor和delegate数量是2对4
            
            for (int i = 0; i < assessorSize; i++) {
                
                // create assessor and assessor account
                Assessor assessor = assessors.get(i);
                
                for (int j = i*2; j < (i*2+2); j++) {
                    
                    // create delegate and delegate account
                    Delegate delegate = delegates.get(j);
                    
                    String subSession = j < 16 ? "A" : "B";
                    String subgroup = Constants.ALPHABET.charAt(j / 4) + "";
                    String assessorSeat = (i % 2 + 1) + "";
                    String delegateSeat = (j % 4 + 1) + "";
                    
                    // create sessionParticipator
                    SessionParticipator sessionParticipator = new SessionParticipator(session, assessor, delegate, subSession, subgroup, assessorSeat, delegateSeat, operator);
                    genericDaoSupport.save(sessionParticipator);
                    
                }
            }
            
            
            
        } else if (assessorSize*2 - delegateSize == 1) {          // 缺少一个Delegate
            
            // 1. 添加正常的2对4数据
            for (int i = 0; i < (assessorSize - 1); i++) {          
                
                Assessor assessor = assessors.get(i);
                for (int j = i*2; j < (i*2+2); j++) {
                    
                    // create delegate and delegate account
                    Delegate delegate = delegates.get(j);
                    
                    String subSession = j < 16 ? "A" : "B";
                    String subgroup = Constants.ALPHABET.charAt(j / 4) + "";
                    String assessorSeat = (i % 2 + 1) + "";
                    String delegateSeat = (j % 4 + 1) + "";
                    
                    // create sessionParticipator
                    SessionParticipator sessionParticipator = new SessionParticipator(session, assessor, delegate, subSession, subgroup, assessorSeat, delegateSeat, operator);
                    genericDaoSupport.save(sessionParticipator);
                    
                }
                
            }
            
            // 2. 添加倒数第一个Assessor和Delegate数据
            int recipOneDelegateIndex = delegateSize - 1;
            Assessor recipOneAssessor = assessors.get(assessorSize - 1);
            Delegate recipOneDelegate = delegates.get(recipOneDelegateIndex);
            
            String subSession = recipOneDelegateIndex < 16 ? "A" : "B";
            String subgroup = Constants.ALPHABET.charAt(recipOneDelegateIndex / 4) + "";
            String assessorSeat = "2";
            String delegateSeat = "3";
            SessionParticipator sessionParticipator = new SessionParticipator(session, recipOneAssessor, recipOneDelegate, subSession, subgroup, assessorSeat, delegateSeat, operator);
            genericDaoSupport.save(sessionParticipator);
            
            
        } else if (assessorSize * 2 - delegateSize == 2) {          // 少两个delegate
            
            // 1. 添加正常的2对4数据
            for (int i = 0; i < (assessorSize - 2); i++) {          
                
                Assessor assessor = assessors.get(i);
                for (int j = i*2; j < (i*2+2); j++) {
                    
                    // create delegate and delegate account
                    Delegate delegate = delegates.get(j);
                    
                    String subSession = j < 16 ? "A" : "B";
                    String subgroup = Constants.ALPHABET.charAt(j / 4) + "";
                    String assessorSeat = (i % 2 + 1) + "";
                    String delegateSeat = (j % 4 + 1) + "";
                    
                    // create sessionParticipator
                    SessionParticipator sessionParticipator = new SessionParticipator(session, assessor, delegate, subSession, subgroup, assessorSeat, delegateSeat, operator);
                    genericDaoSupport.save(sessionParticipator);
                    
                }
                
            }
            
            // 2. 添加倒数第二个Assessor和Delegate
            int recipTwoDelegateIndex = delegateSize - 2;
            Assessor recipTwoAssessor = assessors.get(assessorSize - 2);
            Delegate recipTowDelegate = delegates.get(recipTwoDelegateIndex);
            
            String subSession = recipTwoDelegateIndex < 16 ? "A" : "B";
            String subgroup = Constants.ALPHABET.charAt(recipTwoDelegateIndex / 4) + "";
            String assessorSeat = "1";
            String delegateSeat = "1";
            SessionParticipator sessionParticipator = new SessionParticipator(session, recipTwoAssessor, recipTowDelegate, subSession, subgroup, assessorSeat, delegateSeat, operator);
            genericDaoSupport.save(sessionParticipator);
            
            
            // 3. 添加倒数第一个Assessor和Delegate
            int recipOneDelegateIndex = delegateSize - 1;
            Assessor recipOneAssessor = assessors.get(assessorSize - 1);
            Delegate recipOneDelegate = delegates.get(recipOneDelegateIndex);
            
            subSession = recipOneDelegateIndex < 16 ? "A" : "B";
            subgroup = Constants.ALPHABET.charAt(recipOneDelegateIndex / 4) + "";
            assessorSeat = "2";
            delegateSeat = "3";
            sessionParticipator = new SessionParticipator(session, recipOneAssessor, recipOneDelegate, subSession, subgroup, assessorSeat, delegateSeat, operator);
            genericDaoSupport.save(sessionParticipator);
            
        }
        
    }
    
    /**
     * create session notification
     * 
     * @param session
     */
    private void createSessionNotification(Session session) {
        
        List<EmailTemplate> templates = emailTemplateDao.list();
        for (EmailTemplate template : templates) {
            
            String templateCode = template.getCode();
            
            //===================== Assessor Email =====================
            
            // 1. create assessor welcome letter
            if (StringUtils.equals(templateCode, "assessorWelcome")) {
                SessionNotification notification = new SessionNotification(session, template, null);
                genericDaoSupport.save(notification);
            }
            
            // 2. create Assessor Preparation 任务布置邮件
            if (StringUtils.equals(templateCode, "assessorPreparation")) {
                SessionNotification notification = new SessionNotification(session, template, null);
                genericDaoSupport.save(notification);
            }
            
            // 3. create Who-I-Know notification
            if (StringUtils.equals(templateCode, "whoIKnow")) {
                Date whoIKnowNoticeDate = dateHandler.calculateWorkDay(session.getStartDate(), 9, "13:00");
                SessionNotification notification = new SessionNotification(session, template, whoIKnowNoticeDate);
                genericDaoSupport.save(notification);
            }
            
            // 4. create Certification & the virtual hotel notification
            if (StringUtils.equals(templateCode, "certification")) {
                
                Date certificationNoticeDate = dateHandler.calculateWorkDay(session.getStartDate(), 8, "13:00");
                SessionNotification notification = new SessionNotification(session, template, certificationNoticeDate);
                genericDaoSupport.save(notification);
                
                certificationNoticeDate = dateHandler.calculateWorkDay(session.getStartDate(), 6, "13:00");
                notification = new SessionNotification(session, template, certificationNoticeDate);
                genericDaoSupport.save(notification);
                
            }
    
            //===================== Delegate Email =====================
            
            // 1. create delegate welcome letter
            if (StringUtils.equals(templateCode, "delegateWelcome")) {
                SessionNotification notification = new SessionNotification(session, template, null);
                genericDaoSupport.save(notification);
            }
            
            // 2. Pre-work & online test & Caeer work book 任务布置邮件
            if (StringUtils.equals(templateCode, "taskArrangement")) {
                SessionNotification notification = new SessionNotification(session, template, null);
                genericDaoSupport.save(notification);
            }
            
            // 3. Career work book notification
            if (StringUtils.equals(templateCode, "careerPath")) {
                Date careerPathNoticeDate = dateHandler.calculateWorkDay(session.getStartDate(), 11, "13:00");
                SessionNotification notification = new SessionNotification(session, template, careerPathNoticeDate);
                genericDaoSupport.save(notification);
            }
    
            // 4. Pre-work notification
            if (StringUtils.equals(templateCode, "delegateVirtualHotel")) {
                Date preWorkNoticeDate = dateHandler.calculateWorkDay(session.getStartDate(), 3, "13:00");
                SessionNotification notification = new SessionNotification(session, template, preWorkNoticeDate);
                genericDaoSupport.save(notification);
            }
            
            
            //===================== SuperVisor Email =====================
            if (StringUtils.equals(templateCode, "supervisorUploadFile")) {
                SessionNotification notification = new SessionNotification(session, template, null);
                genericDaoSupport.save(notification);
            }
            
            if (StringUtils.equals(templateCode, "supervisorReportCheck")) {
                SessionNotification notification = new SessionNotification(session, template, null);
                genericDaoSupport.save(notification);
            }
            
            //===================== Delegate Manager Email ===============
            if (StringUtils.equals(templateCode, "delegateGmNotice")) {
              Date now = com.demo2do.core.utils.DateUtils.parseDate(DateFormatUtils.format(session.getStartDate(), "yyyy-MM-dd") + " " + "13:00", "yyyy-MM-dd HH:mm");
              Date occurTime = DateUtils.addDays(now, -1);
              SessionNotification notification = new SessionNotification(session, template, occurTime);
              genericDaoSupport.save(notification);
            }
            
        }
        
    }

    /**
     * create ftp directory
     * 
     * @param session
     * @throws UnsupportedEncodingException 
     */
    @SuppressWarnings({ "unchecked" })
    private void createDirectory(Session session) {
        
        // 1. list delegate
        List<Long> delegateIds = sessionParticipatorDao.listDelegate(session);
        List<Delegate> delegates = delegateDao.list(delegateIds);
        
        // 2. construct delegate name & session name
        List<String> delegateNames = com.demo2do.core.utils.CollectionUtils.extractPropertyList(delegates, "name");
        List<String> sessionNames = Arrays.asList(session.getName());
        
        // 3. call create directory handler
        ftpProcessor.createDirectory(sessionNames, delegateNames);
        
    }
    
    /**
     * bind conference room
     * 
     * @param assessors
     */
    private void bindConferenceRoom(List<Assessor> assessors) {
        
        List<ConferenceRoom> smallZoomRooms = conferenceRoomDao.list(com.ihg.hiex.entity.data.conference.Type.SmallZoom);
        for (int i = 0; i < assessors.size(); i++) {
            
            Assessor assessor = assessors.get(i);
            if (assessor.hasZoomRoom()) {
                continue;
            }
            
            ConferenceRoom room = smallZoomRooms.get(i%8);
            genericDaoSupport.update(assessor.editZoomRoom(room));
            
        }
        
        List<ConferenceRoom> bizconfRooms = conferenceRoomDao.list(com.ihg.hiex.entity.data.conference.Type.BizConf);
        for (int i = 0; i < assessors.size(); i++) {
            
            Assessor assessor = assessors.get(i);
            if (assessor.hasBizconfRoom()) {
                continue;
            }
            
            ConferenceRoom room = bizconfRooms.get(i%8);
            genericDaoSupport.update(assessor.editBizconfRoom(room));
            
        }
        
    }
    
    /**
     * @param session
     * @param name
     * @param startTime
     * @param owner
     * @param conferenceRoom
     * @param target
     * @param type
     */
    private void createSessionMeeting(Session session, String name, Date startTime, Date endTime, Long owner, ConferenceRoom conferenceRoom, Target target, com.ihg.hiex.entity.session.meeting.Type type) {
        
        SessionMeeting sessionMeeting = new SessionMeeting(session, name, startTime, endTime, owner, conferenceRoom, target, type);
        genericDaoSupport.save(sessionMeeting);
        
    }
    
    /* (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#start(com.ihg.hiex.entity.session.Session, java.lang.Long, java.lang.String)
     */
    public void start(Session session, Long operatorId, String operator) {
        
        // 0. Create Directory for assessor & delegate
        // TODO 本地无ftp, 生产环境取消注释这段代码
        this.createDirectory(session);
        
        // 1.1 update session status
        genericDaoSupport.update(session.start(operatorId));
        
        // 1.2 create session event#start
        this.createSessionEvent(session, Type.START, "start", operatorId, operator);
        
        // 3. save assessor session task
        // 3.1 save orientation task of assessor
        Date orientationEndDate = dateHandler.calculateWorkDay(session.getStartDate(), 12, "23:59");
        Date assessorStartDate = dateHandler.calculateWorkDay(session.getStartDate(), 12, "16:00");
        Date assessorEndDate = dateHandler.calculateWorkDay(session.getStartDate(), 12, "17:30");
        this.createSessionTask("Assessor Orientation", session, com.ihg.hiex.entity.session.participator.Type.ASSESSOR, SessionTaskType.MEETING, true, null, null, orientationEndDate, 0);
        this.createSessionTask("Orientation Call", session, com.ihg.hiex.entity.session.participator.Type.ASSESSOR, SessionTaskType.MEETING, true, "Assessor Orientation", assessorStartDate, assessorEndDate, 0);
        
        // 3.2 save Q&A Call Session Task
        Date assessorQaCallStartTime = dateHandler.calculateWorkDay(session.getStartDate(), 2, "16:00");
        Date assessorQaCallEndTime = dateHandler.calculateWorkDay(session.getStartDate(), 2, "17:30");
        this.createSessionTask("Assessor Q&A Call", session, com.ihg.hiex.entity.session.participator.Type.ASSESSOR, SessionTaskType.MEETING, true, "Assessor Preparation", assessorQaCallStartTime, assessorQaCallEndTime, 90);

        
        // 4. save delegate session task
        // 4.1 save orientation task of delegate
        Date delegateStartDate = dateHandler.calculateWorkDay(session.getStartDate(), 12, "14:00");
        Date delegateEndDate = dateHandler.calculateWorkDay(session.getStartDate(), 12, "15:30");
        this.createSessionTask("Delegate Orientation", session, com.ihg.hiex.entity.session.participator.Type.DELEGATE, SessionTaskType.MEETING, true, null, null, orientationEndDate, 90);
        this.createSessionTask("Orientation Call", session, com.ihg.hiex.entity.session.participator.Type.DELEGATE, SessionTaskType.MEETING, true, "Delegate Orientation", delegateStartDate, delegateEndDate, 90);
        
        // 4.2 save Q&A Call Session Task
        Date delegateQaCallStartTime = dateHandler.calculateWorkDay(session.getStartDate(), 2, "14:00");
        Date delegateQaCallEndTime = dateHandler.calculateWorkDay(session.getStartDate(), 2, "15:30");
        this.createSessionTask("Delegate Q&A Call", session, com.ihg.hiex.entity.session.participator.Type.DELEGATE, SessionTaskType.MEETING, true, "Delegate Preparation", delegateQaCallStartTime, delegateQaCallEndTime, 90);
        
        
        
        // 5.1 创建assessor 的sessionTask
        List<Long> assessorIds = sessionParticipatorDao.listAssessor(session);
        List<Assessor> assessors = assessorDao.list(assessorIds);

        this.createAssessorStartTask(session, assessors, assessorStartDate, 0);
        this.createAssessorConfirmTask(session, assessors);
        
        // 5.2 创建delegate的 session task
        List<Long> delegateIds = sessionParticipatorDao.listDelegate(session);
        List<Delegate> delegates = delegateDao.list(delegateIds);
        
        this.createDelegateStartTask(session, delegates, delegateStartDate, 0);
        this.createDelegateConfirmTask(session, delegates);
        
        // 6. save scheduling relation task
        this.createSessionTask("Scheduling Relation", session, com.ihg.hiex.entity.session.participator.Type.ADMINISTRATOR, SessionTaskType.MEETING, true, null, null, null, 0);
        
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#delete(com.ihg.hiex.entity.session.Session, java.lang.Long, java.lang.String)
     */
    public void delete(Session session, Long operatorId, String operator) {
        
        // update session first
        genericDaoSupport.update(session.delete(operatorId));
        
        // delete session participator
        sessionParticipatorDao.delete(session);
        
        // save session event
        this.createSessionEvent(session, Type.DELETE, "delete", operatorId, operator);
        
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#close(com.ihg.hiex.entity.session.Session, java.lang.Long, java.lang.String)
     */
    public void close(Session session, Long operatorId, String operator) {
        
        // update session's status to close
        genericDaoSupport.update(session.close(operatorId));
        
        // save session event
        this.createSessionEvent(session, Type.CLOSE, "close", operatorId, operator);
        
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#edit(com.ihg.hiex.entity.session.Session, java.lang.Long, java.lang.String)
     */
    public void edit(Session session, Long operatorId, String operator) {
        
        // update session first
        genericDaoSupport.update(session);
        
        // save session event
        this.createSessionEvent(session, Type.EDIT, "edit", operatorId, operator);
        
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#openNotice(com.ihg.hiex.entity.session.Session, java.lang.Long, java.lang.String)
     */
    public void openNotice(Session session, Long operatorId, String operator) {
      genericDaoSupport.update(session.openNotice());
    }
    
    /**
     * 
     * @param session
     * @param type
     * @param operatorId
     * @param operator
     */
    private void createSessionEvent(Session session, Type type, String description, Long operatorId, String operator) {
        SessionEvent event = new SessionEvent(session, type, description, operatorId);
        genericDaoSupport.save(event);
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#listParticipator(com.ihg.hiex.entity.session.Session, java.lang.String)
     */
    public Map<String, List<SessionParticipator>> listParticipator(Session session, String subSession) {
        
        List<SessionParticipator> participators = sessionParticipatorDao.list(session, subSession);
        if (CollectionUtils.isEmpty(participators)) {
            return Collections.emptyMap();
        }
        
        return com.demo2do.core.utils.CollectionUtils.constructMapValues(participators, "subgroup");
        
    }
    
    /* (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#listSortParticipator(com.ihg.hiex.entity.session.Session, java.lang.String)
     */
    public Map<String, List<SessionParticipator>> listSortParticipator(Session session, String subSession) {
        
        List<SessionParticipator> participators = sessionParticipatorDao.list(session, subSession);
        if (CollectionUtils.isEmpty(participators)) {
            return Collections.emptyMap();
        }
        
        List<SessionParticipator> sortParticipators = new ArrayList<SessionParticipator>();
        for (SessionParticipator participator : participators) {
            String delegateSeat = participator.getDelegateSeat();
            if (Integer.valueOf(delegateSeat) % 2 == 1) {
                sortParticipators.add(participator);
            }
        }
        
        for (SessionParticipator participator : participators) {
            String delegateSeat = participator.getDelegateSeat();
            if (Integer.valueOf(delegateSeat) % 2 == 0) {
                sortParticipators.add(participator);
            }
        }
        
        return com.demo2do.core.utils.CollectionUtils.constructMapValues(sortParticipators, "subgroup");
        
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#assessorRemove(com.ihg.hiex.entity.session.Session, java.lang.Long)
     */
    public void assessorRemove(Session session, Long assessorId) {
        // remove session participator first
        sessionParticipatorDao.assessorRemove(session, assessorId);
        
        // remove assess's currentSessionId
        Assessor assessor = genericDaoSupport.load(Assessor.class, assessorId);
        genericDaoSupport.update(assessor.editSessionId(null));
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#delegateRemove(com.ihg.hiex.entity.session.Session, java.lang.Long)
     */
    public void delegateRemove(Session session, Long delegateId) {
        
        // 1. update SessionParticipator
        sessionParticipatorDao.delegateRemove(session, delegateId);
        
        // 2. save SessionParticipatorRecord
        SessionParticipatorRecord record = new SessionParticipatorRecord(session, delegateId);
        genericDaoSupport.save(record);
        
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#addAssessor(com.ihg.hiex.entity.session.Session, com.ihg.hiex.entity.user.Assessor, java.lang.String, java.lang.String, java.lang.String[])
     */
    public void addAssessor(Session session, Assessor assessor, String subSession, String subGroup, String[] seats) {

        // FIXME 当js加上查询assessor逻辑时，进行改动
//        Assessor createdAssessor = this.createAssessor(assessor);
        genericDaoSupport.update(assessor.editSessionId(session.getId()));
        
        // 修改sessionParticipator的assessor
        sessionParticipatorDao.addAssessor(assessor.getId(), assessor.getName(), session, subSession, subGroup, seats);
        
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#addDelegate(com.ihg.hiex.entity.user.Delegate, java.lang.String, java.lang.String, java.lang.String)
     */
    public void addDelegate(Session session, Delegate delegate, String subSession, String subGroup, String seat) {
        
        // 修改sessionParticipator的assessor
        SessionParticipator sessionParticipator = sessionParticipatorDao.load(session, subSession, subGroup, seat);
        genericDaoSupport.update(sessionParticipator.editDelegate(delegate.getId(), delegate.getName()));
        
        // 删除sessionParticipatorRecord记录
        SessionParticipatorRecord record = sessionParticipatorRecordDao.load(session, delegate.getId());
        genericDaoSupport.update(record.disable());
        
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#changeSubSession(com.ihg.hiex.entity.session.Session, java.lang.String, java.lang.String)
     */
    public void changeSubSession(Session session, String subSessionA, String subSessionB) {
        
        // 修改subSessionA中所有participator
        String[] subSessionAGroups = subSessionA.split(",");
        sessionParticipatorDao.changeSubSession("A", session, subSessionAGroups);
        
        // 修改subSessionB中所有participator
        String[] subSessionBGroups = subSessionB.split(",");
        sessionParticipatorDao.changeSubSession("B", session, subSessionBGroups);
        
    }
    
    /* (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#confirm(com.ihg.hiex.entity.session.Session, com.ihg.hiex.entity.session.task.SessionTask, java.lang.Long, java.lang.String)
     */
    public void confirm(Session session, SessionTask task, Long operatorId, String operator) {
        
        // 1 save session event
        this.createSessionEvent(session, Type.CONFIRM, "confirm", operatorId, operator);
        
        // 2 scheduling Relation task 设为finish
        genericDaoSupport.update(task.status(com.ihg.hiex.entity.session.task.Status.FINISH));
        
    }
    
    /**
     * 
     * @param name
     * @param session
     * @param target
     * @param type
     * @param group
     * @param parent
     * @param startDate
     * @param endDate
     */
    private void createSessionTask(String name, Session session, com.ihg.hiex.entity.session.participator.Type target,
                                   SessionTaskType type, boolean group, String parent, Date startDate, Date endDate, int minutes) {
        SessionTask task = new SessionTask(name, session, target, type, group, parent, startDate, endDate, minutes);
        genericDaoSupport.save(task);
    }
    
    /**
     * 
     * @param name
     * @param session
     * @param assessor
     * @param parent
     */
    private void createSessionTask(String name, Session session, Assessor assessor, String parent, SessionTaskType type, boolean group, int minutes) {
        SessionTask task = new SessionTask(name, session, assessor, parent, type, group, minutes);
        genericDaoSupport.save(task);
    }
    
    /**
     * @param name
     * @param session
     * @param assessor
     * @param parent
     * @param type
     * @param group
     * @param startDate
     * @param endDate
     */
    private void createSessionTask(String name, Session session, Assessor assessor, String parent, SessionTaskType type, boolean group, Date startDate, Date endDate, int minutes) {
        SessionTask task = new SessionTask(name, session, assessor, parent, type, group, startDate, endDate, minutes);
        genericDaoSupport.save(task);
    }
    
    /**
     * 
     * @param name
     * @param session
     * @param delegate
     * @param parent
     * @param type
     * @param group
     */
    private void createSessionTask(String name, Session session, Delegate delegate, String parent, SessionTaskType type, boolean group, int minutes) {
        SessionTask task = new SessionTask(name, session, delegate, parent, type, group, minutes);
        genericDaoSupport.save(task);
    }
    
    /**
     * @param name
     * @param session
     * @param delegate
     * @param parent
     * @param type
     * @param group
     * @param startDate
     * @param endDate
     */
    private void createSessionTask(String name, Session session, Delegate delegate, String parent, SessionTaskType type, boolean group, Date startDate, Date endDate, int minutes) {
        SessionTask task = new SessionTask(name, session, delegate, parent, type, group, null, endDate, minutes);
        genericDaoSupport.save(task);
    }
    
    /**
     * @param session
     * @param assessors
     * @param assessorStartDate
     */
    private void createAssessorStartTask(Session session, List<Assessor> assessors, Date assessorStartDate, int minutes) {
        
        Date endDate = dateHandler.calculateWorkDay(session.getStartDate(), 9, "23:59");
        
        for(Assessor assessor : assessors) {
            
            // 1. create What is Career Insight
            SessionTask taskCareerTask = new SessionTask("What is Career Insight", session, assessor, "Assessor Orientation", com.ihg.hiex.entity.session.participator.Type.ASSESSOR, SessionTaskType.MEETING, true, null, assessorStartDate, minutes);
            genericDaoSupport.save(taskCareerTask);
            
            // 2. create Who I know
            SessionTask task = new SessionTask("Who I Know", session, assessor, null, SessionTaskType.OTHER, false, null, endDate, minutes);
            genericDaoSupport.save(task);
            
        }
        
    }
    
    /**
     * @param session
     * @param delegates
     * @param delegateStartDate
     */
    private void createDelegateStartTask(Session session, List<Delegate> delegates, Date delegateStartDate, int minutes) {
        
        for (Delegate delegate : delegates) {
            SessionTask taskCareerTask = new SessionTask("What is Career Insight", session, delegate, "Delegate Orientation", com.ihg.hiex.entity.session.participator.Type.DELEGATE, SessionTaskType.MEETING, true, null, delegateStartDate, minutes);
            genericDaoSupport.save(taskCareerTask);
        }
        
    }
    
    /**
     * 
     * @param session
     * @param assessors
     */
    private void createAssessorConfirmTask(Session session, List<Assessor> assessors) {
        
        Date endDate = dateHandler.calculateWorkDay(session.getStartDate(), 3, "23:59");
        
        for(Assessor assessor : assessors) {
            
            // 1 创建Assessor Preparation Task
            this.createSessionTask("Assessor Preparation", session, assessor, null, SessionTaskType.OTHER, false, 0);
            
            // 2 创建Certification Task
            this.createSessionTask("Certificate", session, assessor, "Assessor Preparation", SessionTaskType.OTHER, false, null, endDate, 0);
            
            // 3 创建How to evaluate delegates Session Task
            this.createSessionTask("How to evaluate delegates", session, assessor, "Certificate", SessionTaskType.OTHER, false, null, endDate, 0);
            
            // 4 创建What are the exercises Session Task
            this.createSessionTask("What are the exercises", session, assessor, "Certificate", SessionTaskType.OTHER, false, null, endDate, 0);
            
            // 5 创建How to write the report Session Task
            this.createSessionTask("How to write the report", session, assessor, "Certificate", SessionTaskType.OTHER, false, null, endDate, 0);
            
            // 6 创建Final Test Session Task
            this.createSessionTask("Final Test", session, assessor, "Certificate", SessionTaskType.OTHER, false, null, endDate, 0);
            
            // 7 创建Assessor The Virtual Hotel Session Task
            this.createSessionTask("Assessor The Virtual Hotel", session, assessor, "Assessor Preparation", SessionTaskType.OTHER, false, null, endDate, 0);
            
        }
        
    }
    
    /**
     * 
     * @param session
     * @param delegates
     */
    private void createDelegateConfirmTask(Session session, List<Delegate> delegates) {
        
        Date endDate = dateHandler.calculateWorkDay(session.getStartDate(), 5, "23:59");
        
        for (Delegate delegate : delegates) {
            
            // 1 创建Delegate Preparation Task
            this.createSessionTask("Delegate Preparation", session, delegate, null, SessionTaskType.OTHER, false, 0);
            
            // 2 创建Career Path Session Task
            this.createSessionTask("Career Path", session, delegate, "Delegate Preparation", SessionTaskType.OTHER, false, null, endDate, 0);
            
            // 3 创建Evaluation Session Task
            this.createSessionTask("Evaluation", session, delegate, "Delegate Preparation", SessionTaskType.OTHER, false, null, endDate, 0);
            
            // 4 创建Wave Evaluation Session Task
            this.createSessionTask("Wave Evaluation", session, delegate, "Evaluation", SessionTaskType.OTHER, false, null, endDate, 0);
            
            // 5 创建Swift Evaluation Session Task
            this.createSessionTask("Swift Evaluation", session, delegate, "Evaluation", SessionTaskType.OTHER, false, null, endDate, 0);
            
            // 6 创建Delegate The Virtual Hotel Session Task
            this.createSessionTask("Delegate The Virtual Hotel", session, delegate, "Delegate Preparation", SessionTaskType.OTHER, false, null, endDate, 0);
            
        }
        
    }
    
    /* (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#listFacilitator(com.ihg.hiex.entity.session.Session)
     */
    public List<SessionFacilitator> listFacilitator(Session session) {
        return sessionFacilitatorDao.list(session);
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#listAssessor(com.ihg.hiex.entity.session.Session)
     */
    public List<Assessor> listAssessor(Session session) {
        List<Long> assessorIds = sessionParticipatorDao.listAssessor(session);
        return assessorDao.list(assessorIds);
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#listDelegate(com.ihg.hiex.entity.session.Session)
     */
    public List<Delegate> listDelegate(Session session) {
        List<Long> delegateIds = sessionParticipatorDao.listDelegate(session);
        return delegateDao.list(delegateIds);
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#listDelegate(com.ihg.hiex.entity.user.Administrator)
     */
    public List<Delegate> listDelegate(Administrator administrator) {
        List<Session> sessions = sessionDao.list(administrator);
        List<Long> delegateIds = sessionParticipatorDao.listDelegate(sessions);
        return delegateDao.list(delegateIds);
    }
    
    /* (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#listDelegate(com.ihg.hiex.entity.session.Session, com.ihg.hiex.entity.user.Assessor)
     */
    @SuppressWarnings("unchecked")
    public List<Delegate> listDelegate(Session session, Assessor assessor) {
        
        // 1. 列出所有已删除的Delegate
        List<SessionParticipatorRecord> records = sessionParticipatorRecordDao.list(session);
        List<Long> deleteDelegateIds = com.demo2do.core.utils.CollectionUtils.extractPropertyList(records, "delegateId");
        List<Delegate> delegates = delegateDao.list(deleteDelegateIds); 
        
        // 2. 列出delegate和assessor了解关系
        for (Delegate delegate : delegates) {
            KnowingRelation knowingRelation = knowingRelationDao.load(session, assessor, delegate);
            if (knowingRelation != null && knowingRelation.getKnowingLevel() != null && knowingRelation.getKnowingLevel().isKnowWell()) {
                delegate.setKnowWell(true);
            }
        }
        
        return delegates;
        
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#listSessionTaks(com.ihg.hiex.entity.session.Session, com.ihg.hiex.entity.session.participator.Type)
     */
    public Map<String, Map<String, SessionTask>> listSessionTaks(Session session, com.ihg.hiex.entity.session.participator.Type type) {
        
        // list session all assessor's sessionTask
        List<SessionTask> sessionTasks = sessionDao.listSessionTask(session, type);
        Map<String, List<SessionTask>> tasks = com.demo2do.core.utils.CollectionUtils.constructMapValues(sessionTasks, "name");
        
        // Map key->taskName, value->Map<userId, sessionTask>
        Map<String, Map<String, SessionTask>> result = new HashMap<String, Map<String, SessionTask>>();
        for(Entry<String, List<SessionTask>> task : tasks.entrySet()) {
            Map<String, SessionTask> sessionTask = type.equals(com.ihg.hiex.entity.session.participator.Type.ASSESSOR) ? this.getAssessorTask(task.getValue()) : this.getDelegateTask(task.getValue());
            result.put(task.getKey(), sessionTask);
        }
        
        return result;
        
    }
    
    /**
     * 
     * @param sessionTasks
     * @return
     */
    private Map<String, SessionTask> getAssessorTask(List<SessionTask> sessionTasks) {
        Map<String, SessionTask> tasks = new HashMap<String, SessionTask>();
        for(SessionTask sessionTask : sessionTasks) {
            if(sessionTask.getAssessor() == null) {
                tasks.put("all", sessionTask);
            } else {
                tasks.put(sessionTask.getAssessor().getId().toString(), sessionTask);
            }
        }
        return tasks;
    }
    
    /* (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#listChildSessionTask(com.ihg.hiex.entity.session.Session, java.lang.String)
     */
    public List<SessionTask> listChildSessionTask(Session session, Assessor assessor, String parent) {
        return sessionTaskDao.listChildTask(session, assessor, parent);
    }
    
    /**
     * 
     * @param sessionTasks
     * @return
     */
    private Map<String, SessionTask> getDelegateTask(List<SessionTask> sessionTasks) {
        Map<String, SessionTask> tasks = new HashMap<String, SessionTask>();
        for(SessionTask sessionTask : sessionTasks) {
            if(sessionTask.getDelegate() == null) {
                tasks.put("all", sessionTask);
            } else {
                tasks.put(sessionTask.getDelegate().getId().toString(), sessionTask);
            }
        }
        return tasks;
    }
    
    /* (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#listAssessorFinishTask(com.ihg.hiex.entity.session.Session, java.lang.String, java.util.List)
     */
    public Map<Long, Long> listAssessorFinishTask(Session session, String parent, List<Assessor> assessors) {
        
        List<FinishTask> tasks = sessionDao.listAssessorSessionTask(session, parent, com.ihg.hiex.entity.session.task.Status.FINISH);
        Map<String, FinishTask> finishTasks = com.demo2do.core.utils.CollectionUtils.constructMapValue(tasks, "userId");
        
        Map<Long, Long> result = new HashMap<Long, Long>();
        for(Assessor assessor : assessors) {
            if(!MapUtils.isEmpty(finishTasks) && finishTasks.containsKey(assessor.getId().toString())) {
                result.put(assessor.getId(), finishTasks.get(assessor.getId().toString()).getFinishCount());
            } else {
                result.put(assessor.getId(), new Long(0));
            }
        }
        return result;
        
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#listDelegateFinishTask(com.ihg.hiex.entity.session.Session, java.lang.String, java.util.List)
     */
    public Map<Long, Long> listDelegateFinishTask(Session session, String parent, List<Delegate> delegates) {
        List<FinishTask> tasks = sessionDao.listDelegateSessionTask(session, parent, com.ihg.hiex.entity.session.task.Status.FINISH);
        Map<String, FinishTask> finishTasks = com.demo2do.core.utils.CollectionUtils.constructMapValue(tasks, "userId");
        
        Map<Long, Long> result = new HashMap<Long, Long>();
        for(Delegate delegate : delegates) {
            if(!MapUtils.isEmpty(finishTasks) && finishTasks.containsKey(delegate.getId().toString())) {
                result.put(delegate.getId(), finishTasks.get(delegate.getId().toString()).getFinishCount());
            } else {
                result.put(delegate.getId(), new Long(0));
            }
        }
        return result;
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#listSessionTask(com.ihg.hiex.entity.session.Session, java.lang.String, com.ihg.hiex.entity.session.participator.Type)
     */
    public List<SessionTask> listSessionTask(Session session, String name,
            com.ihg.hiex.entity.session.participator.Type type) {
        return sessionDao.listSessionTask(session, name, type);
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#listSessionTask(com.ihg.hiex.entity.session.Session, java.lang.String)
     */
    public Map<String, SessionTask> listAssessorSessionTask(Session session, String name) {
        List<SessionTask> sessionTasks = sessionDao.listSessionTask(session, name);
        Map<String, SessionTask> result = com.demo2do.core.utils.CollectionUtils.constructMapValue(sessionTasks, "assessor.id");
        return result;
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#listDelegateSessionTask(com.ihg.hiex.entity.session.Session, java.lang.String)
     */
    public Map<String, SessionTask> listDelegateSessionTask(Session session, String name) {
        List<SessionTask> sessionTasks = sessionDao.listSessionTask(session, name);
        Map<String, SessionTask> result = com.demo2do.core.utils.CollectionUtils.constructMapValue(sessionTasks, "delegate.id");
        return result;
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#listSessionMeeting(com.ihg.hiex.entity.session.Session)
     */
    public Map<String, Map<String, SessionMeeting>> listSessionMeeting(Session session) {
        
        List<SessionMeeting> sessionMeetings = sessionDao.listSessionMeeting(session);
        Map<String, List<SessionMeeting>> meetings = com.demo2do.core.utils.CollectionUtils.constructMapValues(sessionMeetings, "name");
        
        Map<String, Map<String, SessionMeeting>> result = new HashMap<String, Map<String, SessionMeeting>>();
        for(Entry<String, List<SessionMeeting>> meeting : meetings.entrySet()) {
            Map<String, SessionMeeting> sessionMeeting = com.demo2do.core.utils.CollectionUtils.constructMapValue(meeting.getValue(), "target");
            result.put(meeting.getKey(), sessionMeeting);
        }
        
        return result;
        
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#loadSessionMeeting(java.lang.Long)
     */
    public SessionMeeting loadSessionMeeting(Long meetingId) {
        return genericDaoSupport.load(SessionMeeting.class, meetingId);
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#loadSessionMeeting(com.ihg.hiex.entity.session.Session, java.lang.String, com.ihg.hiex.entity.session.participator.Type)
     */
    public SessionMeeting loadSessionMeeting(Session session, String name, Target target) {
        return sessionDao.loadSessionMeeting(session, name, target);
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#loadSessionEvent(com.ihg.hiex.entity.session.Session, com.ihg.hiex.entity.session.event.Type)
     */
    public SessionEvent loadSessionEvent(Session session, Type type) {
        return sessionDao.loadSessionEvent(session, type);
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#editSessionMeeting(com.ihg.hiex.entity.session.SessionMeeting)
     */
    public void editSessionMeeting(SessionMeeting sessionMeeting) {
        genericDaoSupport.update(sessionMeeting);
    }
    
    /* (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.SessionService#createFacilitator(com.ihg.hiex.entity.session.Session, com.ihg.hiex.entity.session.participator.SessionFacilitator)
     */
    public void createFacilitator(Session session, SessionFacilitator facilitator, FacilitatorConferenceRoom room) {
        
        // 1. check facilitator wheter exist in this session
        SessionFacilitator existFacilitator = sessionFacilitatorDao.loadByEmail(session, facilitator.getEmail());
        if (existFacilitator != null) {
            throw BusinessException.newInstance("400", "该主讲师已存在于当前Session");
        }
        
        // 2. check facilitator's account whether exist
        Account existAccount = accountDao.loadByEmail(facilitator.getEmail());
        if (existAccount != null) {         // 2.1 account exist, update account
            
            if (!existAccount.hasAuthority("FACILITATOR") && !existAccount.hasAuthority("ADMIN")) {
                throw BusinessException.newInstance("500", "该Email已被占用");
            }
            
            if (existAccount.hasAuthority("FACILITATOR")) {
                
                Administrator administrator = administratorDao.loadByEmail(facilitator.getEmail(), Role.FACILITATOR.toString());
                if (!administrator.hasConferenceRoom()) {
                    
                    ConferenceRoom conferenceRoom = new ConferenceRoom(room.getConferenceRoomName(), room.getConferenceRoomUrl(), 
                            com.ihg.hiex.entity.data.conference.Type.WebEx, room.getConferenceRoomAccount(), room.getConferenceRoomPassword(), room.getConferenceRoomDescription());
                    genericDaoSupport.save(conferenceRoom);
                    
                    genericDaoSupport.update(administrator.edit(conferenceRoom));
                    
                }
                
                
            } else if (existAccount.hasAuthority("ADMIN")) {
                
                Administrator administrator = administratorDao.loadByEmail(facilitator.getEmail(), Role.ADMIN.toString());
                if (!administrator.hasConferenceRoom()) {
                    
                    ConferenceRoom conferenceRoom = new ConferenceRoom(room.getConferenceRoomName(), room.getConferenceRoomUrl(), 
                            com.ihg.hiex.entity.data.conference.Type.WebEx, room.getConferenceRoomAccount(), room.getConferenceRoomPassword(), room.getConferenceRoomDescription());
                    genericDaoSupport.save(conferenceRoom);
                    
                    genericDaoSupport.update(administrator.edit(conferenceRoom));
                    
                }
                
                
            }
            
            // 3. save facilitator
            genericDaoSupport.save(facilitator.initialize(session, existAccount));
            
        } else {                            // 2.2 account not exist, save account
            
            Account account = new Account(facilitator);
            genericDaoSupport.save(account.initialize());
            
            // 3.1 save conferenceRoom
            ConferenceRoom conferenceRoom = new ConferenceRoom(room.getConferenceRoomName(), room.getConferenceRoomUrl(), 
                    com.ihg.hiex.entity.data.conference.Type.WebEx, room.getConferenceRoomAccount(), room.getConferenceRoomPassword(), room.getConferenceRoomDescription());
            genericDaoSupport.save(conferenceRoom);
            
            // 3.2 add admin
            Administrator administrator = new Administrator(account, facilitator, conferenceRoom);
            genericDaoSupport.save(administrator);
            
            // 4. save facilitator
            genericDaoSupport.save(facilitator.initialize(session, account));
            
        }
        
        
    }

}
